#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <string>

#define TNUM 4

typedef void (*func_t)(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond);

int tickets = 5;
bool flag = true;

class ThreadData
{
public:
    ThreadData(const std::string &name, func_t func, pthread_mutex_t *mutex, pthread_cond_t *cond) : _name(name), _func(func), _mutex(mutex), _cond(cond) {}

public:
    std::string _name;
    func_t _func;
    pthread_mutex_t *_mutex;
    pthread_cond_t *_cond;
};

void func1(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_mutex_lock(mutex);
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....下载" << std::endl; 
        pthread_mutex_unlock(mutex);
    }
}
void func2(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_mutex_lock(mutex);
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....查看用户" << std::endl; 
        pthread_mutex_unlock(mutex);
    }
}
void func3(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_mutex_lock(mutex);
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....扫描" << std::endl; 
        pthread_mutex_unlock(mutex);
    }
}
void func4(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_mutex_lock(mutex);
        pthread_cond_wait(cond, mutex); //在条件变量下等待
        std::cout<< name  << " runing ....广播" << std::endl; 
        pthread_mutex_unlock(mutex);
    }
}

void *Entry(void *args)
{
    ThreadData *td = (ThreadData *)args;
    td->_func(td->_name, td->_mutex, td->_cond); //调用线程绑定的函数
    delete td;
    return nullptr;
}

int main()
{
    pthread_mutex_t mtx; // 互斥锁
    pthread_cond_t cond; // 条件变量

    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);

    func_t funs[4] = {func1, func2, func3, func4}; //函数指针数组，存储上面4个函数
    pthread_t tids[4];

    // 创建线程
    for (int i = 0; i < TNUM; i++)
    {
        std::string name = "thread ";
        name += std::to_string(i + 1);
        ThreadData *td = new ThreadData(name, funs[i], &mtx, &cond); //创建线程数据对象，存储线aa程的数据以及锁，条件变量信息
        pthread_create(tids + i, nullptr, Entry, (void *)td);
    }
    sleep(5);
    int cnt = 10;
    while (cnt)
    {
        //每隔一秒唤醒一个线程
        std::cout << "wakeup thread ......  " << cnt--  << std::endl; 
        pthread_cond_signal(&cond); //唤醒一个线程
        sleep(1);
    }   
    std::cout << "ctrl done" << std::endl;
    flag = false; //结束线程内的循环
    //走到这里，所有线程依旧处于wait状态，在这里需要再唤醒一次
    pthread_cond_broadcast(&cond); //唤醒所有线程
    
    for (int i = 0; i < TNUM; i++)
    {
        pthread_join(tids[i], nullptr);
        std::cout << "thread " << i + 1 << "   quit....." << std::endl;
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}